package com.huawang.mdesign.model.service.inter;

import com.huawang.business.command.CommandAddType;
import com.huawang.business.command.CommandParameter;
import com.huawang.business.constants.ErrorCode;
import com.huawang.business.constants.ModelConstantURI;
import com.huawang.business.constants.SlotDataType;
import com.huawang.business.dto.*;
import com.huawang.business.dto.graph.ModelInfo;
import com.huawang.business.dto.property.ItemInfo;
import com.huawang.business.entity.ownedproperty.QueryOwnedPropertyForm;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.model.base.ElementNameService;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.*;
import com.huawang.business.service.model.core.add.IModelOperation;
import com.huawang.business.service.model.core.delete.DeleteService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.service.model.core.property.UpdateModelFactory;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.InstanceUtils;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.util.ValidateDataUtil;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.business.vo.PropertyInfoVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.semantics.entity.queryResult.MofResultContainer;
import com.huawang.core.semantics.entity.queryResult.QueryPropertyForm;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.core.semantics.utils.TransformUtil;
import com.huawang.mdesign.model.service.constant.UAFModelConstantURI;
import com.huawang.mdesign.model.service.dto.*;
import com.huawang.mdesign.model.service.util.LogUtil;
import com.huawang.mdesign.model.service.util.uaf.PropertyUtils;
import com.huawang.mdesign.model.service.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ErrorCode.BATCH_CREATE_INSTANCE_EXCEED_MAX_LEVEL;
import static com.huawang.business.constants.ModelActionName.ADD_MODEL;
import static com.huawang.business.constants.ModelActionName.DELETE_MODEL;

@Slf4j
@Service
@Primary
public class PropertyGroupService {

    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private UmlService umlService;

    @Autowired
    private ProjectManager projectManager;

    @Autowired
    private InternalSpecificationService internalSpecificationService;

    @Autowired
    private ModelService modelService;

    @Autowired
    private InternalPropertyService internalPropertyService;

    @Autowired
    private ModelPropertyInfoService modelPropertyInfoService;

    @Autowired
    private InternalModelIconService internalModelIconService;

    @Autowired
    private ElementNameService elementNameService;

    @Autowired
    private TransactionServiceImpl transactionService;

    @Autowired
    private DeleteService deleteService;

    private static final String DIRECTION = "direction";

    public static final String NEGATIVE_ONE = "-1";
    private static final Integer CONSTRAIN_TYPE = 1;
    private static final Integer MAX_LEVEL_LIMIT = 100;

    private static final Integer DEFAULT_SPECIFICATION_VALUE_NUM = 1;

    /**
     * 前端查询slot时，禁止显示的部分配置
     */
    private final Set<String> disableDisplaySlotDefiningFeatureIds =
            new HashSet<>(Arrays.asList(UMLDefinitionConstants.SysML_AbstractRequirement_derived,
                    UMLDefinitionConstants.SysML_AbstractRequirement_derivedFrom,
                    UMLDefinitionConstants.SysML_AbstractRequirement_master,
                    UMLDefinitionConstants.SysML_AbstractRequirement_refinedBy,
                    UMLDefinitionConstants.SysML_AbstractRequirement_satisfiedBy,
                    UMLDefinitionConstants.SysML_AbstractRequirement_tracedTo,
                    UMLDefinitionConstants.SysML_AbstractRequirement_verifiedBy));

    @NotNull
    public List<String> queryApplyConstraints(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("queryApplyConstraints -> projectId: {}, instanceId: {}", projectId, instanceId);
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (instance == null) {
            return Collections.emptyList();
        }

        return internalUmlService.queryListInstanceProperty(projectId, instance,
                        UMLDefinitionConstants.Element_constraints).stream().map(BasicRElement::getId)
                .collect(Collectors.toList());
    }

    @NotNull
    public List<ElementApplyConstraintVo> queryElementApplyConstraints(String projectId, List<String> instanceIds) {
        LogUtil.printOnlineLogs("projectId: {}, instanceIds: {}", projectId, instanceIds);
        List<MetaClassInstance> instanceList = internalUmlService.fetchInstanceByIds(instanceIds, projectId);
        if (CollectionUtils.isEmpty(instanceList)) {
            return Collections.emptyList();
        }
        List<ModelPropertyInfo> modelPropertyInfoList = modelPropertyInfoService.createModelPropertyInfoList(projectId,
                instanceList, Stream.of(UMLDefinitionConstants.Element_constraints).collect(Collectors.toList()));
        return modelPropertyInfoList.stream().map(model -> {
            ElementApplyConstraintVo elementApplyConstraintVo = new ElementApplyConstraintVo();
            elementApplyConstraintVo.setInstance(model.getInstanceId());
            elementApplyConstraintVo.setConstraintElementIds(model.queryListInstanceValue(UMLDefinitionConstants.Element_constraints)
                    .stream().map(BasicRElement::getId).collect(Collectors.toList()));
            return elementApplyConstraintVo;
        }).collect(Collectors.toList());
    }

    @NotNull
    public List<ElementApplyConstraintVo> queryAllConstraintAndConstrainedElements(String projectId) {
        LogUtil.printOnlineLogs("projectId", projectId);
        // 查询项目中所有的Constraint
        List<MetaClassInstance> allConstraintList = internalUmlService.querySpecifiedInstanceList(projectId,
                UMLDefinitionConstants.Constraint, false);
        List<ModelPropertyInfo> modelPropertyInfoList = modelPropertyInfoService.createModelPropertyInfoList(projectId,
                allConstraintList, Stream.of(UMLDefinitionConstants.Constraint_constrainedElement).collect(Collectors.toList()));
        return modelPropertyInfoList.stream().map(model -> {
            ElementApplyConstraintVo elementApplyConstraintVo = new ElementApplyConstraintVo();
            elementApplyConstraintVo.setInstance(model.getInstanceId());
            elementApplyConstraintVo.setConstraintElementIds(model.queryListInstanceValue(UMLDefinitionConstants.Constraint_constrainedElement)
                    .stream().map(BasicRElement::getId).collect(Collectors.toList()));
            return elementApplyConstraintVo;
        }).collect(Collectors.toList());
    }

    /**
     * 找到实例的所有classifier（以及其父类）
     *
     * @param projectId
     * @param instance
     * @return
     */
    @NotNull
    public Set<String> queryAllClassifier(@NotNull final String projectId,
                                          @NotNull final MetaClassInstance instance) {
        LogUtil.printSerializeOnlineLogs("queryAllClassifier -> projectId: {}, instance: {}", projectId, instance);
        final QueryPropertyForm queryPropertyForm = this.internalUmlService
                .getQueryPropertyForm(instance, UMLDefinitionConstants.InstanceSpecification_classifier);
        final List<MetaClassInstance> classifiers = TransformUtil.transformObjectToListInstance(
                this.internalUmlService.queryProperty(projectId, queryPropertyForm).values(queryPropertyForm));
        if (CollectionUtils.isEmpty(classifiers)) {
            return Collections.emptySet();
        }
        return classifiers.stream()
                .flatMap(it -> this.internalUmlService.findGeneralIdsCascade(projectId, it.getId(), true).stream())
                .collect(Collectors.toSet());
    }

    /**
     * 找到实例的所有classifier（以及其父类）
     *
     * @param projectId
     * @param instanceId
     * @return
     */
    @NotNull
    public Set<String> queryAllClassifier(@NotNull final String projectId,
                                          @NotNull final String instanceId) {
        LogUtil.printOnlineLogs("queryAllClassifier -> projectId: {}, instanceId: {}", projectId, instanceId);
        final MetaClassInstance instance = this.internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(instance)) {
            return Collections.emptySet();
        }
        return this.queryAllClassifier(projectId, instance);
    }

    /**
     * 查询实例某个分类器对应的所有插槽
     *
     * @param projectId
     * @param instanceId
     * @param classifierId
     * @return java.util.List<com.huawang.mdesign.model.service.vo.SlotVo>
     * @author xz
     * @date 2023/05/25 11:06
     */
    @NotNull
    public List<SlotVo> queryInstanceSlots(@NotNull final String projectId,
                                           @NotNull final String instanceId,
                                           @NotNull final String classifierId) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}, classifierId: {}", projectId, instanceId, classifierId);
        final Map<String, MetaClassInstance> metaClassInstanceMap = this.internalUmlService
                .fetchInstances(Stream.of(instanceId, classifierId).collect(Collectors.toList()), projectId);
        final MetaClassInstance instance = metaClassInstanceMap.get(instanceId);
        final MetaClassInstance classifier = metaClassInstanceMap.get(classifierId);
        if (Objects.isNull(instance) || Objects.isNull(classifier)) {
            return Collections.emptyList();
        }

        List<MetaClassInstance> allAttributes = internalUmlService.queryListInstanceProperty(projectId, classifier,
                UMLDefinitionConstants.Class_ownedAttribute);
        // 当分类器为DataType类型时
        if (allAttributes.size() == 0 && internalUmlService.checkInstanceType(projectId, classifier, UMLDefinitionConstants.DataType)) {
            allAttributes = internalUmlService.queryListInstanceProperty(projectId, classifier,
                    UMLDefinitionConstants.Classifier_attribute);
        }

        // 子类重定义了父类的属性，子类在展示时父类的属性应该被过滤
        Set<String> allClassifiers = queryAllClassifier(projectId, instanceId);
        if (allClassifiers.size() > 1) {
            Map<String, ModelPropertyInfo> modelPropertyInfoMap = modelPropertyInfoService.createModelPropertyInfoMap(projectId,
                    allAttributes, Stream.of(UMLDefinitionConstants.A_redefinedProperty_property_property).collect(Collectors.toList()));
            allAttributes = allAttributes.stream().filter(it ->
                    CollectionUtils.isEmpty(modelPropertyInfoMap.get(it.getId()).queryListInstanceValue(UMLDefinitionConstants.A_redefinedProperty_property_property))).collect(Collectors.toList());
        }
        return makeSlotVos(projectId, instance, allAttributes);
    }

    /**
     * 设置slotVo的dataype
     *
     * @param projectId
     * @param attribute
     * @param vo
     * @return void
     * @author xz
     * @date 2023/05/25 11:04
     */
    public void fillDataType(String projectId, MetaClassInstance attribute, SlotVo vo) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, attribute: {}, vo: {}", projectId, attribute, vo);
        String typeName = internalSpecificationService.getPropertyTypeName(projectId, attribute);
        switch (typeName) {
            case UMLDefinitionConstants.LiteralBoolean:
                vo.setDataType(SlotDataType.BOOLEAN.value());
                break;
            case UMLDefinitionConstants.InstanceValue: {
                MetaClassInstance type = internalUmlService.queryInstanceProperty(projectId, attribute,
                        UMLDefinitionConstants.TypedElement_type);
                vo.setMoreBtnCondition(UMLDefinitionConstants.InstanceSpecification);
                vo.setDataType(SlotDataType.INSTANCE.value());
                if (type != null && internalUmlService.checkInstanceType(projectId, type,
                        UMLDefinitionConstants.Enumeration)) {
                    vo.setDataType(SlotDataType.ENUM.value());
                    vo.setItems(internalUmlService.queryListInstanceProperty(projectId, type,
                            UMLDefinitionConstants.Enumeration_ownedLiteral).stream().map(literal -> {
                        ItemInfo itemInfo = new ItemInfo();
                        itemInfo.setValue(literal.getId());
                        itemInfo.setLabel(internalUmlService.queryStringProperty(projectId, literal,
                                UMLDefinitionConstants.NamedElement_name));
                        itemInfo.setEnLabel(itemInfo.getLabel());
                        return itemInfo;
                    }).collect(Collectors.toList()));
                }

                break;
            }
            case UMLDefinitionConstants.ElementValue: {
                MetaClassInstance type = internalUmlService.queryInstanceProperty(projectId, attribute,
                        UMLDefinitionConstants.TypedElement_type);
                vo.setDataType(SlotDataType.INSTANCE.value());
                if (type != null) {
                    vo.setMoreBtnCondition(type.getId());
                }

                break;
            }
            default:
                vo.setDataType(SlotDataType.STRING.value());
                break;
        }
    }

    /**
     * @param projectId
     * @param instanceSpecification
     * @param attributes
     * @return java.util.List<com.huawang.mdesign.model.service.vo.SlotVo>
     * @author xz
     * @date 2023/05/25 11:44
     */
    @NotNull
    private List<SlotVo> makeSlotVos(@NotNull final String projectId,
                                     final MetaClassInstance instanceSpecification,
                                     @NotNull final List<MetaClassInstance> attributes) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceSpecification: {}, attributes: {}", projectId,
                instanceSpecification, attributes);
        if (Objects.isNull(instanceSpecification)) {
            final List<ModelPropertyInfo> attributeModels = modelPropertyInfoService.createModelPropertyInfoList(projectId, attributes,
                    Stream.of(UMLDefinitionConstants.Property_defaultValue, UMLDefinitionConstants.NamedElement_name,
                            UMLDefinitionConstants.TypedElement_type).collect(Collectors.toList()));

            return attributeModels.stream().map(model -> {
                SlotVo vo = new SlotVo();
                vo.setPropertyId(model.getInstanceId());
                vo.setPropertyIcon(internalModelIconService.queryIcon(projectId, model.getInstance()));
                vo.setName(model.queryStringValue(UMLDefinitionConstants.NamedElement_name));
                vo.setHidden(queryAttributeIsDisable((model.getInstanceId())));
                vo.setIsMultiplicity(internalUmlService.isMultiplicity(projectId, model.getInstanceId()));
                vo.setNullable(PropertyUtils.getNullable(internalUmlService.queryPropertyLower(projectId,
                        model.getInstanceId()), model.getInstanceId()));
                fillDataTypeByModel(projectId, model, vo);
                return vo;
            }).collect(Collectors.toList());
        }
        final List<String> attributeIds = attributes.stream().map(BasicRElement::getId).collect(Collectors.toList());
        final List<ModelPropertyInfo> attributeModels = modelPropertyInfoService.createModelPropertyInfoList(
                projectId, attributes,
                Stream.of(UMLDefinitionConstants.Property_defaultValue,
                        UMLDefinitionConstants.NamedElement_name,
                        UMLDefinitionConstants.TypedElement_type).collect(Collectors.toList()));
        final Map<String, MetaClassInstance> definingFeatureId2SlotMap =
                this.getDefiningFeatureId2SlotMap(projectId, instanceSpecification, attributeIds);
        final Map<String, List<MetaClassInstance>> slotValueMap =
                this.getSlotValueMap(projectId, definingFeatureId2SlotMap.values().stream().distinct().collect(Collectors.toList()));
        final Map<String, String> iconMap = this.modelPropertyInfoService.queryIconBatch(projectId, attributes);
        final Map<String, Boolean> isMultiplicityMap = this.internalUmlService.isMultiplicity(projectId,
                attributeIds, slotValueMap, definingFeatureId2SlotMap);
        final Map<String, Integer> lowerMap = this.internalUmlService.queryPropertyLower(projectId, attributeIds);
        return attributeModels.stream()
                .map(model -> {
                    final String attributeId = model.getInstanceId();
                    final SlotVo vo = new SlotVo();
                    vo.setPropertyId(attributeId);
                    vo.setPropertyIcon(iconMap.getOrDefault(attributeId, ""));
                    vo.setName(model.queryStringValue(UMLDefinitionConstants.NamedElement_name));
                    vo.setHidden(this.disableDisplaySlotDefiningFeatureIds.contains(attributeId));
                    vo.setIsMultiplicity(isMultiplicityMap.get(attributeId));
                    vo.setNullable(PropertyUtils.getNullable(lowerMap.get(attributeId), attributeId));
                    this.fillDataTypeByModel(projectId, model, vo);
                    if (definingFeatureId2SlotMap.containsKey(attributeId)) {
                        final MetaClassInstance slot = definingFeatureId2SlotMap.get(attributeId);
                        final String slotId = slot.getId();
                        vo.setSlotId(slotId);
                        final List<MetaClassInstance> values = slotValueMap.get(slotId);
                        List<SlotValueVo> slotValueVoList = this.internalSpecificationService.queryValueFromValueSpecification(projectId, values)
                                .entrySet().stream().map(entry -> {
                                    final SlotValueVo valueVo = new SlotValueVo();
                                    final ValueSpecificationInfo valueSpecificationInfo = entry.getValue();
                                    valueVo.setValue(valueSpecificationInfo.getValue() != null ?
                                            valueSpecificationInfo.getValue() : valueSpecificationInfo.getElementId());
                                    valueVo.setId(entry.getKey());
                                    return valueVo;
                                }).collect(Collectors.toList());
                        vo.setValues(slotValueVoList);
                    }
                    return vo;
                }).collect(Collectors.toList());
    }

    private static boolean queryAttributeIsDisable(String attributeId) {
        LogUtil.printOnlineLogs("attributeId: ", attributeId);
        List<String> disableAttributeIds =
                Arrays.asList(UMLDefinitionConstants.SysML_AbstractRequirement_derived,
                        UMLDefinitionConstants.SysML_AbstractRequirement_derivedFrom,
                        UMLDefinitionConstants.SysML_AbstractRequirement_master,
                        UMLDefinitionConstants.SysML_AbstractRequirement_refinedBy,
                        UMLDefinitionConstants.SysML_AbstractRequirement_satisfiedBy,
                        UMLDefinitionConstants.SysML_AbstractRequirement_tracedTo,
                        UMLDefinitionConstants.SysML_AbstractRequirement_verifiedBy);
        return disableAttributeIds.contains(attributeId);
    }

    @NotNull
    private Map<String, List<MetaClassInstance>> getSlotValueMap(@NotNull final String projectId,
                                                                 @NotNull final List<MetaClassInstance> slots) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, slots: {}", projectId, slots);
        final Map<String, List<MetaClassInstance>> result = new HashMap<>();
        final QueryPropertyForm queryPropertyForm = this.internalUmlService
                .getQueryPropertyForm(slots, UMLDefinitionConstants.Slot_value);
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
        for (MetaClassInstance slot : slots) {
            final String slotId = slot.getId();
            final List<MetaClassInstance> values = mofResultContainer
                    .queryListInstanceProperty(slotId, UMLDefinitionConstants.Slot_value);
            result.put(slotId, values);
        }
        return result;
    }

    @NotNull
    private Map<String, MetaClassInstance> getDefiningFeatureId2SlotMap(@NotNull final String projectId,
                                                                        @NotNull final MetaClassInstance instanceSpecification,
                                                                        @NotNull final List<String> attributeIds) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceSpecification: {}, attributeIds: {}", projectId,
                instanceSpecification, attributeIds);
        final Set<String> attributeIdSet = new HashSet<>(attributeIds);
        final QueryPropertyForm querySlotForm = this.internalUmlService
                .getQueryPropertyForm(instanceSpecification, UMLDefinitionConstants.InstanceSpecification_slot);
        final List<MetaClassInstance> slots = TransformUtil.transformObjectToListInstance(
                this.internalUmlService.queryProperty(projectId, querySlotForm).values(querySlotForm));
        final QueryPropertyForm queryDefiningFeatureForm = this.internalUmlService
                .getQueryPropertyForm(slots, UMLDefinitionConstants.Slot_definingFeature);
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryDefiningFeatureForm);
        return slots.stream()
                .filter(slot -> {
                    final MetaClassInstance definingFeature = mofResultContainer
                            .queryInstanceProperty(slot.getId(), UMLDefinitionConstants.Slot_definingFeature);
                    return Objects.nonNull(definingFeature) && attributeIdSet.contains(definingFeature.getId());
                }).collect(Collectors.toMap(slot -> {
                    final MetaClassInstance feature = mofResultContainer
                            .queryInstanceProperty(slot.getId(), UMLDefinitionConstants.Slot_definingFeature);
                    return Objects.requireNonNull(feature).getId();
                }, Function.identity(), (v1, v2) -> v2));
    }

    /**
     * 填充SlotVo的dataType字段
     *
     * @param projectId
     * @param model
     * @param vo
     */
    private void fillDataTypeByModel(@NotNull final String projectId,
                                     @NotNull final ModelPropertyInfo model,
                                     @NotNull final SlotVo vo) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, model: {}, vo: {}", projectId, model, vo);
        final MetaClassInstance type = model.queryInstanceValue(UMLDefinitionConstants.TypedElement_type);
        if (type == null) {
            vo.setDataType(SlotDataType.STRING.value());
            return;
        }
        final String typeName = this.internalSpecificationService.getValuespecificationType(projectId, type);
        switch (typeName) {
            case UMLDefinitionConstants.LiteralBoolean:
                vo.setDataType(SlotDataType.BOOLEAN.value());
                break;
            case UMLDefinitionConstants.LiteralInteger: {
                vo.setDataType(SlotDataType.INTEGER.value());
                break;
            }
            case UMLDefinitionConstants.LiteralReal: {
                vo.setDataType(SlotDataType.REAL.value());
                break;
            }
            case UMLDefinitionConstants.InstanceValue: {
                if (internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Enumeration)) {
                    vo.setDataType(SlotDataType.ENUM.value());
                    vo.setItems(internalUmlService.queryListInstanceProperty(projectId, type,
                            UMLDefinitionConstants.Enumeration_ownedLiteral).stream().map(literal -> {
                        ItemInfo itemInfo = new ItemInfo();
                        itemInfo.setValue(literal.getId());
                        itemInfo.setLabel(internalUmlService.queryStringProperty(projectId, literal,
                                UMLDefinitionConstants.NamedElement_name));
                        itemInfo.setEnLabel(itemInfo.getLabel());
                        return itemInfo;
                    }).collect(Collectors.toList()));
                } else {
                    vo.setMoreBtnCondition(UMLDefinitionConstants.InstanceSpecification);
                    vo.setDataType(SlotDataType.INSTANCE.value());
                }
                break;
            }
            case UMLDefinitionConstants.ElementValue: {
                vo.setDataType(SlotDataType.INSTANCE.value());
                vo.setMoreBtnCondition(type.getId());
                break;
            }
            default:
                vo.setDataType(SlotDataType.STRING.value());
                break;
        }
    }

    /**
     * 根据class的属性，创建实例的插槽
     *
     * @param projectId
     * @param propertyId class的属性id
     * @param parentId   实例id
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author xz
     * @date 2023/05/25 16:47
     */
    @NotNull
    public ModelResultVo createSlotByProperty(String projectId,
                                              String propertyId,
                                              String parentId) {
        LogUtil.printOnlineLogs("projectId: {}, propertyId: {}, parentId: {}", projectId, propertyId, parentId);
        MetaClassInstance property = internalUmlService.fetchInstance(propertyId, projectId);
        if (property == null) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }
        return getModelResultVo(projectId, parentId, property);
    }

    @NotNull
    public ModelResultVo createOrUpdateSlotValue(CreateOrUpdateSlotValue dto) {
        LogUtil.printSerializeOnlineLogs("createOrUpdateSlotValue -> dto: ", dto);
        final String projectId = dto.getProjectId();
        final Map<String, MetaClassInstance> metaClassInstanceMap = this.internalUmlService.fetchInstances(
                Stream.of(dto.getSlotId(), dto.getPropertyId()).collect(Collectors.toList()), projectId);
        final MetaClassInstance slot = metaClassInstanceMap.get(dto.getSlotId());
        final MetaClassInstance property = metaClassInstanceMap.get(dto.getPropertyId());
        if (Objects.isNull(slot) || Objects.isNull(property)) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }
        final ModelResultVo modelResultVo = new ModelResultVo();
        final QueryPropertyForm slotQueryForm = this.internalUmlService
                .getQueryPropertyForm(slot, UMLDefinitionConstants.Slot_value);
        final QueryPropertyForm attributeQueryForm = this.internalUmlService
                .getQueryPropertyForm(property,
                        Stream.of(UMLDefinitionConstants.MultiplicityElement_upper,
                                UMLDefinitionConstants.TypedElement_type).collect(Collectors.toList()));
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(
                projectId, Stream.of(slotQueryForm, attributeQueryForm).collect(Collectors.toList()));
        final List<MetaClassInstance> oldSlotValues = TransformUtil.transformObjectToListInstance(
                mofResultContainer.values(slotQueryForm));
        final String upper = mofResultContainer
                .queryStringProperty(dto.getPropertyId(), UMLDefinitionConstants.MultiplicityElement_upper);
        // 校验slot值与property多重性兼容
        boolean isCreate = StringUtils.isEmpty(dto.getValueSpecificationId());
        if (isCreate) {
            // 只有创建时需要校验+
            MetaClassInstance type = mofResultContainer.queryInstanceProperty(property.getId(),
                    UMLDefinitionConstants.TypedElement_type);
            this.checkSlotValueUpper(dto, oldSlotValues, type, upper);
        }
        final Map<String, String> oldSlotValueToValueIdMap = getOldValue(projectId, oldSlotValues);
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {
            if (dto.getValue() instanceof Collection) {
                if (CollectionUtils.isEmpty((Collection<?>) dto.getValue())) {
                    // 集合为空时，则删除
                    this.deleteService.deleteModel(projectId, slot.getId());
                } else {
                    final List<String> slotValues = TransformUtil.transformObjectToListString(dto.getValue());
                    Set<String> slotValueSet = new HashSet<>(slotValues);
                    List<String> needDeleteSlotValueModelIds = oldSlotValueToValueIdMap.keySet().stream().
                            filter(e -> !slotValueSet.contains(e)).map(oldSlotValueToValueIdMap::get).collect(Collectors.toList());
                    deleteService.deleteModels(projectId, needDeleteSlotValueModelIds);
                    slotValues.stream()
                            .filter(value -> value != null && !oldSlotValueToValueIdMap.containsKey(value))
                            .forEach(it -> this.internalSpecificationService.createValueSpecificationBySlot(
                                    projectId, slot, it, null, dto.getValueSpecificationId())
                            );
                }
            } else {
                internalSpecificationService.createValueSpecificationBySlot(projectId, slot, dto.getValue(), null,
                        dto.getValueSpecificationId());
            }

            transactionService.commit(projectId);
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }

        return modelResultVo;
    }

    @NotNull
    private Map<String, String> getOldValue(@NotNull final String projectId,
                                            @NotNull final List<MetaClassInstance> oldSlotValues) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, oldSlotValues: {}", projectId, oldSlotValues);
        final List<MetaClassInstance> elementValues = oldSlotValues.stream()
                .filter(it -> this.internalUmlService.checkInstanceType(projectId, it, UMLDefinitionConstants.ElementValue))
                .collect(Collectors.toList());
        final List<MetaClassInstance> instanceValues = oldSlotValues.stream()
                .filter(it -> this.internalUmlService.checkInstanceType(projectId, it, UMLDefinitionConstants.InstanceValue))
                .collect(Collectors.toList());
        final QueryPropertyForm queryElementForm = this.internalUmlService
                .getQueryPropertyForm(elementValues, UMLDefinitionConstants.ElementValue_element);
        final QueryPropertyForm queryInstanceForm = this.internalUmlService
                .getQueryPropertyForm(instanceValues, UMLDefinitionConstants.InstanceValue_instance);
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(
                projectId,
                Stream.of(queryElementForm, queryInstanceForm).collect(Collectors.toList()));
        Map<String, String> map = new HashMap<>();
        for (MetaClassInstance oldSlotValue : oldSlotValues) {
            Stream.of(mofResultContainer.queryInstanceProperty(oldSlotValue.getId(), UMLDefinitionConstants.ElementValue_element),
                            mofResultContainer.queryInstanceProperty(oldSlotValue.getId(), UMLDefinitionConstants.InstanceValue_instance)).
                    collect(Collectors.toList()).stream().filter(Objects::nonNull).forEach(e -> map.put(e.getId(), oldSlotValue.getId()));
        }
        return map;
    }

    private void checkSlotValueUpper(@NotNull final CreateOrUpdateSlotValue dto,
                                     @NotNull final List<MetaClassInstance> oldSlotValues,
                                     @Nullable MetaClassInstance type,
                                     @Nullable final String upper) {
        LogUtil.printSerializeOnlineLogs("dto: {}, oldSlotValues: {}, type: {}, upper: {}", dto, oldSlotValues, type, upper);
        if (Objects.equals(upper, NEGATIVE_ONE)) {
            return;
        }
        final Object value = dto.getValue();
        int upperInt = Objects.nonNull(upper) ? Integer.parseInt(upper) : 0;
        if (value instanceof Collection) {
            if (((Collection<?>) value).size() > upperInt) {
                throw AbortExecutionException.build(ErrorCode.SLOT_VALUE_EXCEED_PROPERTY_MULTIPLICITY);
            }
        } else {
            int oldValueSize = oldSlotValues.size();
            if (oldValueSize + 1 > upperInt) {
                throw AbortExecutionException.build(ErrorCode.SLOT_VALUE_EXCEED_PROPERTY_MULTIPLICITY);
            }
        }
    }

    public List<String> queryTags(String projectId, String instanceId) {
        return Optional.ofNullable(internalUmlService.fetchInstance(instanceId, projectId))
                .map(instance ->
                        internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.InstanceSpecification) ?
                        getTags(projectId, instance) :
                        Optional.ofNullable(getTagsOfNotInstance(projectId, instance))
                                .filter(CollectionUtils::isNotEmpty)
                                .map(e -> e.stream().map(MetaClassInstance::getId).collect(Collectors.toList()))
                                .orElse(Collections.emptyList()))
                .orElse(Collections.emptyList());
    }

    public List<MetaClassInstance> getTagsOfNotInstance(String projectId, MetaClassInstance instance) {
        String instanceId = instance.getId();
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(
                projectId,
                this.internalUmlService.getQueryPropertyForm(
                        instance,
                        Stream.of(UMLDefinitionConstants.Element_appliedStereotype,
                                UMLDefinitionConstants.Element_appliedStereotypeInstance).collect(Collectors.toList())
                )
        );
        final MetaClassInstance appliedStereotypeInstance = mofResultContainer
                .queryInstanceProperty(instanceId, UMLDefinitionConstants.Element_appliedStereotypeInstance);
        if (Objects.isNull(appliedStereotypeInstance)) {
            return Collections.emptyList();
        }

        List<MetaClassInstance> slots = new ArrayList<>();
        if (internalUmlService.checkInstanceType(projectId, instance,
                UMLDefinitionConstants.SysML_AbstractRequirement)) {
            mofResultContainer.addMofPropertyResult(this.internalUmlService.queryProperty(
                    projectId,
                    this.internalUmlService.getQueryPropertyForm(
                            appliedStereotypeInstance, UMLDefinitionConstants.InstanceSpecification_slot
                    )
            ));
            slots = mofResultContainer.queryListInstanceProperty(
                    appliedStereotypeInstance.getId(), UMLDefinitionConstants.InstanceSpecification_slot);
            mofResultContainer.addMofPropertyResult(
                    this.internalUmlService.queryProperty(
                            projectId,
                            this.internalUmlService.getQueryPropertyForm(slots, UMLDefinitionConstants.Slot_definingFeature))
            );
            slots.removeIf(slot -> {
                final MetaClassInstance definingFeature = mofResultContainer
                        .queryInstanceProperty(slot.getId(), UMLDefinitionConstants.Slot_definingFeature);
                if (Objects.isNull(definingFeature)) {
                    return false;
                }
                final String definingFeatureId = definingFeature.getId();
                return !Objects.equals(definingFeatureId, UMLDefinitionConstants.SysML_AbstractRequirement_id) &&
                        !Objects.equals(definingFeatureId, UMLDefinitionConstants.SysML_AbstractRequirement_text);
            });
        } else {
            final List<MetaClassInstance> appliedStereotypes = mofResultContainer.queryListInstanceProperty(
                    instanceId, UMLDefinitionConstants.Element_appliedStereotype);
            if (CollectionUtils.isNotEmpty(appliedStereotypes)) {
                slots = internalUmlService.queryListInstanceProperty(projectId, appliedStereotypeInstance,
                        UMLDefinitionConstants.InstanceSpecification_slot);
            }
        }
        return slots;
    }

    private List<String> getTags(String projectId, MetaClassInstance instance) {
        final List<String> stereotypeIds = queryAllStereotypeByInstance(projectId, instance).stream()
                .filter(it -> !StringUtils.equals(it, UMLDefinitionConstants.SysML_AbstractRequirement) &&
                        !StringUtils.equals(it, UMLDefinitionConstants.Customization_NumberOwner)
                ).collect(Collectors.toList());
        final Map<String, MetaClassInstance> stereotypeMap = this.internalUmlService
                .fetchInstanceByIds(stereotypeIds, projectId).stream()
                .collect(Collectors.toMap(BasicRElement::getId, Function.identity(), (a, b) -> a));
        List<SlotVo> slotList = stereotypeIds.stream()
                .filter(it -> Objects.nonNull(stereotypeMap.get(it)))
                .flatMap(stereotypeId -> this.queryPropertySlots(projectId, instance, stereotypeMap.get(stereotypeId)).stream())
                .filter(it -> StringUtils.isNotEmpty(it.getSlotId()))
                .collect(Collectors.toList());
        return slotList.stream().map(SlotVo::getSlotId).collect(Collectors.toList());
    }

    /**
     * 尝试将Object转换为List，若不是数组则返回本身
     *
     * @param object
     * @return
     */
    @NotNull
    private static List<Object> tryTransformObjectToListObject(Object object) {
        LogUtil.printOnlineLogs("object: ", object);
        if (!(object instanceof Collection)) {
            return Stream.of(object).collect(Collectors.toList());
        }
        // 2. 将object的内容转成MetaClassInstance格式返回
        return Stream.of((Collection<?>) object).flatMap(Collection::stream)
                .collect(Collectors.toList());
    }

    @NotNull
    public List<String> queryTaggedValues(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("queryTaggedValues -> projectId: {}, instanceId: {}", projectId, instanceId);
        List<TaggedValueVo> taggedValueVos =
                queryTaggedValues(projectId, Collections.singletonList(instanceId));
        if (CollectionUtils.isEmpty(taggedValueVos)) {
            return new ArrayList<>();
        }

        return taggedValueVos.get(0).getSlotIds();
    }

    @NotNull
    public List<TaggedValueVo> queryTaggedValues(String projectId, List<String> instanceIds) {
        LogUtil.printOnlineLogs("projectId: {}, instanceIds: {}", projectId, instanceIds);
        List<MetaClassInstance> instances = internalUmlService.fetchInstanceByIds(instanceIds, projectId);
        if (CollectionUtils.isEmpty(instances)) {
            return Collections.emptyList();
        }

        List<ModelPropertyInfo> modelPropertyInfoList = modelPropertyInfoService.createModelPropertyInfoList(projectId,
                instances,
                Stream.of(UMLDefinitionConstants.InstanceSpecification_slot,
                        UMLDefinitionConstants.Element_appliedStereotype,
                        UMLDefinitionConstants.Element_appliedStereotypeInstance).collect(Collectors.toList()));
        List<String> requirements = new ArrayList<>();
        List<MetaClassInstance> appliedStereotypeInstances = new ArrayList<>();
        Map<String, String> appliedStereotypeInstanceMap = new HashMap<>();
        Map<String, List<MetaClassInstance>> slotMap = new HashMap<>();
        for (ModelPropertyInfo modelPropertyInfo : modelPropertyInfoList) {
            if (modelPropertyInfo.checkInstanceType(UMLDefinitionConstants.InstanceSpecification)) {
                slotMap.put(modelPropertyInfo.getInstanceId(),
                        modelPropertyInfo.queryListInstanceValue(UMLDefinitionConstants.InstanceSpecification_slot));
            } else {
                final MetaClassInstance appliedStereotypeInstance = modelPropertyInfo
                        .queryInstanceValue(UMLDefinitionConstants.Element_appliedStereotypeInstance);
                if (appliedStereotypeInstance != null) {
                    appliedStereotypeInstanceMap.put(appliedStereotypeInstance.getId(),
                            modelPropertyInfo.getInstanceId());
                    appliedStereotypeInstances.add(appliedStereotypeInstance);
                }
                if (modelPropertyInfo.checkInstanceType(UMLDefinitionConstants.SysML_AbstractRequirement)) {
                    requirements.add(modelPropertyInfo.getInstanceId());
                }
            }

        }

        List<ModelPropertyInfo> appliedStereotypeInstanceModels =
                modelPropertyInfoService.createModelPropertyInfoList(projectId,
                        appliedStereotypeInstances,
                        Stream.of(UMLDefinitionConstants.InstanceSpecification_slot,
                                UMLDefinitionConstants.Element_appliedStereotype,
                                UMLDefinitionConstants.Element_appliedStereotypeInstance).collect(Collectors.toList()));
        List<MetaClassInstance> requirementSlots = new ArrayList<>();
        for (ModelPropertyInfo appliedStereotypeInstanceModel : appliedStereotypeInstanceModels) {
            if (appliedStereotypeInstanceMap.containsKey(appliedStereotypeInstanceModel.getInstanceId())) {
                String instanceId = appliedStereotypeInstanceMap.get(appliedStereotypeInstanceModel.getInstanceId());
                List<MetaClassInstance> slots =
                        appliedStereotypeInstanceModel.queryListInstanceValue(UMLDefinitionConstants.InstanceSpecification_slot);
                QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(slots, UMLDefinitionConstants.Slot_value);
                MofResultContainer mofResultContainer = internalUmlService.queryProperty(projectId, queryPropertyForm);
                slots = slots.stream().filter(it -> {
                    List<MetaClassInstance> slotValues = mofResultContainer.queryListInstanceProperty(it.getId(), UMLDefinitionConstants.Slot_value);
                    return CollectionUtils.isNotEmpty(slotValues);

                }).collect(Collectors.toList());
                slotMap.put(instanceId, slots);
                fillRequirementSlots(requirements, appliedStereotypeInstanceMap, requirementSlots, appliedStereotypeInstanceModel, slots);
            }

        }

        final MofResultContainer mofResultContainer = internalUmlService.getMofResultContainer(projectId,
                requirementSlots,
                UMLDefinitionConstants.Slot_definingFeature);
        return instanceIds.stream().map(it -> {
            TaggedValueVo taggedValueVo = new TaggedValueVo();
            taggedValueVo.setInstanceId(it);
            if (slotMap.containsKey(it)) {
                fillTaggedValueSlotIds(requirements, slotMap, mofResultContainer, it, taggedValueVo);
            }

            return taggedValueVo;
        }).collect(Collectors.toList());
    }

    private static void fillRequirementSlots(List<String> requirements,
                                             Map<String, String> appliedStereotypeInstanceMap,
                                             List<MetaClassInstance> requirementSlots,
                                             ModelPropertyInfo appliedStereotypeInstanceModel,
                                             List<MetaClassInstance> slots) {
        LogUtil.printSerializeOnlineLogs("requirements: {}, appliedStereotypeInstanceMap: {}, requirementSlots: {}, slots: {}",
                requirements, appliedStereotypeInstanceMap, requirementSlots, slots);
        if (requirements.contains(appliedStereotypeInstanceMap.get(appliedStereotypeInstanceModel.getInstanceId()))) {
            requirementSlots.addAll(slots);
        }
    }

    private static void fillTaggedValueSlotIds(List<String> requirements, Map<String, List<MetaClassInstance>> slotMap, MofResultContainer mofResultContainer, String it, TaggedValueVo taggedValueVo) {
        LogUtil.printSerializeOnlineLogs("requirements: {}, it: {}, taggedValueVo: {}", requirements, it, taggedValueVo);
        List<String> slotIds = slotMap.get(it).stream().map(BasicRElement::getId).collect(Collectors.toList());
        if (requirements.contains(it)) {
            taggedValueVo.setSlotIds(slotIds.stream().filter(slotId -> {
                MetaClassInstance def = mofResultContainer.queryInstanceProperty(slotId,
                        UMLDefinitionConstants.Slot_definingFeature);
                return def != null;
            }).collect(Collectors.toList()));
        } else {
            taggedValueVo.setSlotIds(slotIds);
        }
    }

    /**
     * 返回属性组的columns属性设置的属性内容
     *
     * @param projectId
     * @param propertyGroupId
     * @return
     */
    @NotNull
    public List<PropertyInfoVo> queryPropertyGroupColumns(@NotNull String projectId,
                                                          @NotNull String propertyGroupId) {
        LogUtil.printOnlineLogs("queryPropertyGroupColumns -> projectId: {}, propertyGroupId: {}", projectId, propertyGroupId);
        MetaClassInstance propertyGroup = internalUmlService.fetchInstance(propertyGroupId, projectId);
        if (propertyGroup == null) {
            return Collections.emptyList();
        }

        List<String> columns = internalUmlService.queryListStringProperty(projectId, propertyGroup,
                UMLDefinitionConstants.Customization_PropertyGroup_columns);
        final Map<String, PropertyInfoVo> propertyInfoVos = this.createPropertyInfoVos(projectId, columns);
        return new ArrayList<>(propertyInfoVos.values());
    }

    @NotNull
    private Map<String, PropertyInfoVo> createPropertyInfoVos(@NotNull final String projectId,
                                                              @NotNull final List<String> columns) {
        LogUtil.printOnlineLogs("projectId: {}, columns: {}", projectId, columns);
        final Map<String, PropertyInfoVo> propertyInfoVoMap = columns.stream()
                .map(column -> {
                    final PropertyInfoVo propertyInfoVo = new PropertyInfoVo();
                    propertyInfoVo.setKey(column);
                    return propertyInfoVo;
                }).collect(Collectors.toMap(PropertyInfoVo::getKey, Function.identity(), (a, b) -> a));
        final List<String> noCnNameConfigColumns = new LinkedList<>();
        for (String column : columns) {
            final String name = internalPropertyService.queryPropertyCnName(column);
            if (StringUtils.isNotEmpty(name)) {
                propertyInfoVoMap.get(column).setName(name);
            } else {
                noCnNameConfigColumns.add(column);
            }
        }
        if (CollectionUtils.isNotEmpty(noCnNameConfigColumns)) {
            final Map<String, MetaClassInstance> metaClassInstanceMap =
                    this.internalUmlService.fetchInstances(noCnNameConfigColumns, projectId);
            final List<MetaClassInstance> properties = new ArrayList<>(metaClassInstanceMap.values());
            final QueryPropertyForm queryPropertyForm = this.internalUmlService
                    .getQueryPropertyForm(properties, UMLDefinitionConstants.NamedElement_name);
            final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
            for (String noCnNameConfigColumn : noCnNameConfigColumns) {
                final String name = mofResultContainer.queryStringProperty(noCnNameConfigColumn, UMLDefinitionConstants.NamedElement_name);
                propertyInfoVoMap.get(noCnNameConfigColumn).setName(Objects.nonNull(name) ? name : "");
            }
        }
        return propertyInfoVoMap;
    }

    @NotNull
    private PropertyInfoVo createPropertyInfoVo(ModelPropertyInfo model) {
        LogUtil.printSerializeOnlineLogs("model: ", model);
        PropertyInfoVo vo = new PropertyInfoVo();
        vo.setKey(model.getInstanceId());
        final String name = internalPropertyService.queryPropertyCnName(model.getInstanceId());
        if (StringUtils.isNotEmpty(name)) {
            vo.setName(name);
        } else {
            vo.setName(model.queryStringValue(UMLDefinitionConstants.NamedElement_name));
        }

        return vo;
    }

    @NotNull
    public List<PropertyGroupVo> queryPropertyGroups(@NotNull String projectId,
                                                     @NotNull String instanceId) {
        LogUtil.printOnlineLogs("queryPropertyGroups -> projectId: {}, instanceId: {}", projectId, instanceId);
        if (Objects.isNull(projectManager.getProject(projectId))) {
            return Collections.emptyList();
        }
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (instance == null) {
            return Collections.emptyList();
        }

        Set<String> typeUri = internalUmlService.getGivenTypes(projectId, instance);

        List<MetaClassInstance> customizations = internalUmlService.queryPropertyRelationInstanceBatch(projectId,
                new ArrayList<>(typeUri),
                UMLDefinitionConstants.Customization_Customization_customizationTarget);
        if (customizations.isEmpty()) {
            return new ArrayList<>();
        }

        List<MetaClassInstance> properties = modelPropertyInfoService.createModelPropertyInfoList(projectId, customizations,
                        Stream.of(UMLDefinitionConstants.Class_ownedAttribute).collect(Collectors.toList()))
                .stream().flatMap(it -> it.queryListInstanceValue(UMLDefinitionConstants.Class_ownedAttribute).stream())
                .collect(Collectors.toList());
        final List<MetaClassInstance> propertyGroups = properties.stream()
                .filter(it -> internalUmlService.checkInstanceType(projectId, it, UMLDefinitionConstants.Customization_PropertyGroup))
                .collect(Collectors.toList());
        final QueryPropertyForm queryPropertyForm = this.internalUmlService.getQueryPropertyForm(
                propertyGroups,
                Stream.of(UMLDefinitionConstants.NamedElement_name,
                        UMLDefinitionConstants.Customization_PropertyGroup_titleBarDescription).collect(Collectors.toList()));
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
        return new ArrayList<>(initPropertyGroupVos(propertyGroups, mofResultContainer).values());
    }

    /**
     * 查询属性组行信息
     *
     * @param projectId
     * @param propertyGroupId
     * @param instanceId
     * @param rowIds
     * @return com.huawang.mdesign.model.service.vo.PropertyGroupVo
     * @author xz
     * @date 2023/05/25 17:17
     */
    @Nullable
    public PropertyGroupVo queryRowValues(@NotNull String projectId,
                                          @NotNull String propertyGroupId,
                                          @NotNull String instanceId,
                                          @NotNull List<String> rowIds) {
        LogUtil.printOnlineLogs("projectId: {}, propertyGroupId: {}, instanceId: {}, rowIds: {}", projectId, propertyGroupId,
                instanceId, rowIds);
        final Map<String, MetaClassInstance> metaClassInstanceMap = this.internalUmlService.fetchInstances(
                Stream.of(instanceId, propertyGroupId).collect(Collectors.toList()), projectId);
        final MetaClassInstance instance = metaClassInstanceMap.get(instanceId);
        final MetaClassInstance propertyGroup = metaClassInstanceMap.get(propertyGroupId);
        if (Objects.isNull(instance) || Objects.isNull(propertyGroup)) {
            return null;
        }
        final MofResultContainer mofResultContainer = this.preQueryDataForQueryRowValues(projectId, propertyGroup);
        final PropertyGroupVo vo = initPropertyGroupVos(Collections.singletonList(propertyGroup), mofResultContainer)
                .get(propertyGroupId);
        final List<MetaClassInstance> rowInstances = this.getPropertyGroupRows(
                projectId, propertyGroupId, rowIds, mofResultContainer, instance);
        return fillRowVoByColumns(projectId, propertyGroupId, rowInstances, mofResultContainer, vo);
    }

    @NotNull
    private PropertyGroupVo fillRowVoByColumns(@NotNull final String projectId,
                                               @NotNull final String propertyGroupId,
                                               @NotNull final List<MetaClassInstance> rowInstances,
                                               @NotNull final MofResultContainer mofResultContainer,
                                               @NotNull final PropertyGroupVo vo) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, propertyGroupId: {}, rowInstances: {}", projectId, propertyGroupId,
                rowInstances);
        if (CollectionUtils.isEmpty(rowInstances)) {
            return vo;
        }
        final List<String> columns = mofResultContainer.queryListStringProperty(
                propertyGroupId, UMLDefinitionConstants.Customization_PropertyGroup_columns);
        if (CollectionUtils.isEmpty(columns)) {
            return vo;
        }
        final Map<String, String> nameMap = this.elementNameService.fetchNameBatch(projectId, rowInstances);
        List<DiagramTableTileVo> rowVos = rowInstances.stream()
                .map(row -> {
                    final DiagramTableTileVo rowVo = new DiagramTableTileVo();
                    rowVo.setName(nameMap.get(row.getId()));
                    rowVo.setInstanceId(row.getId());
                    final ModelInfo cur = internalUmlService.fetchModelInfoValue(projectId, row);
                    if (Objects.nonNull(cur)) {
                        rowVo.setIcon(cur.getIcon());
                    }
                    List<PropertyConfigDto> configs = columns.stream().map(key -> {
                        PropertyConfigDto dto = new PropertyConfigDto();
                        dto.setKey(key);
                        dto.setStereotype(internalUmlService.checkIsStereotypeProperty(projectId, key));
                        return dto;
                    }).collect(Collectors.toList());
                    rowVo.setCells(modelService.createPropertyConfigByBatch(projectId, row, configs, null));
                    return rowVo;
                }).collect(Collectors.toList());
        vo.setRows(rowVos);
        return vo;
    }

    @NotNull
    private MofResultContainer preQueryDataForQueryRowValues(@NotNull final String projectId,
                                                             @NotNull final MetaClassInstance propertyGroup) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, propertyGroup: {}", projectId, propertyGroup);
        final QueryPropertyForm queryPropertyForm = this.internalUmlService.getQueryPropertyForm(
                propertyGroup,
                Stream.of(UMLDefinitionConstants.NamedElement_name,
                        UMLDefinitionConstants.Customization_PropertyGroup_properties,
                        UMLDefinitionConstants.Customization_PropertyGroup_titleBarDescription,
                        UMLDefinitionConstants.Customization_PropertyGroup_columns).collect(Collectors.toList())
        );
        return this.internalUmlService.queryProperty(projectId, queryPropertyForm);
    }

    /**
     * 获取属性组要显示的行元素
     */
    @NotNull
    private List<MetaClassInstance> getPropertyGroupRows(@NotNull final String projectId,
                                                         @NotNull final String propertyGroupId,
                                                         @NotNull final List<String> rowIds,
                                                         @NotNull final MofResultContainer mofResultContainer,
                                                         @NotNull final MetaClassInstance instance) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, propertyGroupId: {}, rowIds: {}, instance: {}",
                projectId, propertyGroupId, rowIds, instance);
        final String propertyGroupPropertyName = mofResultContainer.queryListStringProperty(propertyGroupId,
                UMLDefinitionConstants.Customization_PropertyGroup_properties).stream().findFirst().orElse(null);
        if (Objects.isNull(propertyGroupPropertyName)) {
            return Collections.emptyList();
        }
        return CollectionUtils.isNotEmpty(rowIds) ?
                this.internalUmlService.fetchInstanceByIds(rowIds, projectId) :
                this.internalUmlService.queryListInstanceProperty(projectId, instance, propertyGroupPropertyName);
    }

    @NotNull
    private static Map<String, PropertyGroupVo> initPropertyGroupVos(@NotNull final List<MetaClassInstance> propertyGroups,
                                                                     @NotNull final MofResultContainer mofResultContainer) {
        LogUtil.printSerializeOnlineLogs("propertyGroups: ", propertyGroups);
        final Map<String, PropertyGroupVo> result = new HashMap<>();
        for (MetaClassInstance propertyGroup : propertyGroups) {
            final String propertyGroupId = propertyGroup.getId();
            final PropertyGroupVo propertyGroupVo = new PropertyGroupVo();
            propertyGroupVo.setGroupId(propertyGroupId);
            propertyGroupVo.setName(
                    mofResultContainer.queryStringProperty(propertyGroupId, UMLDefinitionConstants.NamedElement_name));
            propertyGroupVo.setDescription(
                    mofResultContainer.queryStringProperty(
                            propertyGroupId, UMLDefinitionConstants.Customization_PropertyGroup_titleBarDescription));
            result.put(propertyGroupId, propertyGroupVo);
        }
        return result;
    }

    @NotNull
    public List<ConstraintVo> queryInstanceConstraints(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("queryInstanceConstraints -> projectId: {}, instanceId: {}", projectId, instanceId);
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(instance)) {
            return Collections.emptyList();
        }
        List<MetaClassInstance> constraints = internalUmlService.queryListInstanceProperty(projectId, instance,
                UMLDefinitionConstants.Element_constraints);
        if (CollectionUtils.isEmpty(constraints)) {
            return Collections.emptyList();
        }

        // 首先批量查询
        QueryPropertyForm queryPropertyForm = new QueryPropertyForm();
        constraints.forEach(constraint -> {
            queryPropertyForm.put(constraint, UMLDefinitionConstants.NamedElement_name);
            if (internalUmlService.checkInstanceType(projectId, constraint, UMLDefinitionConstants.DurationConstraint)) {
                queryPropertyForm.add(constraint, UMLDefinitionConstants.DurationConstraint_specification);
            } else if (internalUmlService.checkInstanceType(projectId, constraint, UMLDefinitionConstants.TimeConstraint)) {
                queryPropertyForm.add(constraint, UMLDefinitionConstants.TimeConstraint_specification);
            } else {
                queryPropertyForm.add(constraint, UMLDefinitionConstants.Constraint_specification);
            }
        });
        if (queryPropertyForm.isEmpty()) {
            return new ArrayList<>();
        }
        MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId, queryPropertyForm);
        List<MetaClassInstance> specifications = constraints.stream().map(constraint -> {
            final MetaClassInstance specification = getSpecification(projectId, mofResultContainer, constraint);
            return Objects.nonNull(specification) ? specification : null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, ValueSpecificationInfo> valueSpecificationInfoMap = this.internalSpecificationService
                .queryValueFromValueSpecification(projectId, specifications);

        return constraints.stream().map(constraint -> {
            ConstraintVo constraintVo = new ConstraintVo();
            final MetaClassInstance specification = getSpecification(projectId, mofResultContainer, constraint);
            constraintVo.setMetaClass(constraint.getMetaClass().getId());
            constraintVo.setConstraintId(constraint.getId());
            constraintVo.setConstraintName(mofResultContainer.queryStringProperty(constraint.getId(),
                    UMLDefinitionConstants.NamedElement_name));
            if (Objects.nonNull(specification)) {
                constraintVo.setSpecificationId(specification.getId());
                constraintVo.setValueSpecificationInfo(valueSpecificationInfoMap.get(specification.getId()));
            }
            return constraintVo;
        }).collect(Collectors.toList());
    }

    @Nullable
    private MetaClassInstance getSpecification(@NotNull final String projectId,
                                               @NotNull final MofResultContainer mofResultContainer,
                                               @NotNull final MetaClassInstance constraint) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, constraint: {}", projectId, constraint);
        MetaClassInstance specification;
        if (internalUmlService.checkInstanceType(projectId, constraint, UMLDefinitionConstants.DurationConstraint)) {
            specification = mofResultContainer.queryInstanceProperty(constraint.getId(),
                    UMLDefinitionConstants.DurationConstraint_specification);
        } else if (internalUmlService.checkInstanceType(projectId, constraint, UMLDefinitionConstants.TimeConstraint)) {
            specification = mofResultContainer.queryInstanceProperty(constraint.getId(),
                    UMLDefinitionConstants.TimeConstraint_specification);
        } else {
            specification = mofResultContainer.queryInstanceProperty(constraint.getId(),
                    UMLDefinitionConstants.Constraint_specification);
        }
        return specification;
    }

    @NotNull
    public ModelResultVo createConstraintAndApply(String projectId, String instanceId, Integer constrainType, List<String> appliedStereotypes) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceId: {}, constrainType: {}", projectId, instanceId,
                constrainType);
        final ModelResultVo modelResultVo = new ModelResultVo();
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(instance)) {
            return modelResultVo;
        }

        final LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {
            final AddModelDTO dto = new AddModelDTO();
            dto.setParentId(instanceId);
            dto.setMetaclass(UMLDefinitionConstants.Constraint);
            dto.setProjectId(projectId);
            dto.setType(CommandAddType.MODEL.getCode());
            dto.setApplyStereotypes(appliedStereotypes);
            MetaClassInstance constraint;
            // constrainType为1时，选择为时间段约束
            if (Objects.equals(constrainType, CONSTRAIN_TYPE)) {
                // 创建时间段约束
                dto.setMetaclass(UMLDefinitionConstants.DurationConstraint);
            }

            IModelOperation modelOperation = umlService.fetchModelOperation(dto.getMetaclass(),
                    dto.getOperation());
            if (modelOperation == null) {
                throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR);
            }
            constraint = modelOperation.doHandler(dto);

            umlService.updateModel(projectId, constraint.getId(), UMLDefinitionConstants.Constraint_constrainedElement,
                    Collections.singletonList(instance));

            modelResultVo.setInstanceId(constraint.getId());
            transactionService.commit(projectId);
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }

        return modelResultVo;
    }

    @NotNull
    public List<String> queryAllStereotype(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("queryAllStereotype -> projectId: {}, instanceId: {}", projectId, instanceId);
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(instance)) {
            return Collections.emptyList();
        }

        return queryAllStereotypeByInstance(projectId, instance);
    }

    @NotNull
    public List<String> queryAllStereotypeByInstance(String projectId, MetaClassInstance instance) {
        LogUtil.printSerializeOnlineLogs("queryAllStereotypeByInstance -> projectId: {}, instance: {}", projectId, instance);
        // 度量类型和度量单位不应该有标签，在此处也即不用查到stereotype
        if (internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.Customization_QuantityKind)
                || internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.Customization_Unit)) {
            return Collections.emptyList();
        }
        final List<MetaClassInstance> stereotypes = this.getAllStereotypes(projectId, instance);
        final MofResultContainer mofResultContainer = this.preQueryDataForNoBaseStereotypes(projectId, stereotypes);
        final List<MetaClassInstance> noBasePropertyStereotypes = getNoBasePropertyStereotypes(stereotypes, mofResultContainer);
        return noBasePropertyStereotypes.stream().map(MetaClassInstance::getId).distinct().collect(Collectors.toList());
    }

    /**
     * 获取Classifier_feature中没有base_开头的stereotype
     */
    @NotNull
    private static List<MetaClassInstance> getNoBasePropertyStereotypes(@NotNull final List<MetaClassInstance> stereotypes,
                                                                        @NotNull final MofResultContainer mofResultContainer) {
        LogUtil.printSerializeOnlineLogs("stereotypes: ", stereotypes);
        final List<MetaClassInstance> noBasePropertyStereotypes = new ArrayList<>();
        for (MetaClassInstance stereotype : stereotypes) {
            final List<MetaClassInstance> ownedAttributes = mofResultContainer.queryListInstanceProperty(
                    stereotype.getId(), UMLDefinitionConstants.Classifier_feature);
            if (ownedAttributes.isEmpty()) {
                continue;
            }
            final List<String> nameList = ownedAttributes.stream().map(attribute ->
                            mofResultContainer.queryStringProperty(attribute.getId(), UMLDefinitionConstants.NamedElement_name))
                    .filter(Objects::nonNull).collect(Collectors.toList());
            if (nameList.stream().anyMatch(it -> !it.startsWith("base_"))) {
                noBasePropertyStereotypes.add(stereotype);
            }
        }
        return noBasePropertyStereotypes;
    }

    @NotNull
    private MofResultContainer preQueryDataForNoBaseStereotypes(@NotNull final String projectId,
                                                                @NotNull final List<MetaClassInstance> stereotypes) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, stereotypes: {}", projectId, stereotypes);
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(
                projectId, this.internalUmlService.getQueryPropertyForm(stereotypes, UMLDefinitionConstants.Classifier_feature));
        final List<MetaClassInstance> queryNameFeatures = stereotypes.stream()
//                .filter(it -> mofResultContainer
//                        .queryListInstanceProperty(it.getId(), UMLDefinitionConstants.Classifier_feature)
//                        .size() > 1)
                .flatMap(it -> mofResultContainer
                        .queryListInstanceProperty(it.getId(), UMLDefinitionConstants.Classifier_feature).stream())
                .distinct()
                .collect(Collectors.toList());
        final QueryPropertyForm queryNameForm = this.internalUmlService
                .getQueryPropertyForm(queryNameFeatures, UMLDefinitionConstants.NamedElement_name);
        mofResultContainer.addMofPropertyResult(this.internalUmlService.queryProperty(projectId, queryNameForm));
        return mofResultContainer;
    }

    @NotNull
    private List<MetaClassInstance> getAllStereotypes(@NotNull final String projectId, @NotNull final MetaClassInstance instance) {
        LogUtil.printSerializeOnlineLogs("getAllStereotypes -> projectId: {}, instance: {}", projectId, instance);
        final List<String> appliedStereotypes = new ArrayList<>(instance.getAppliedStereotypes());
        appliedStereotypes.addAll(appliedStereotypes.stream()
                .flatMap(it -> this.internalUmlService.findGeneralIdsCascade(projectId, it, false).stream())
                .distinct()
                .collect(Collectors.toList()));
        return this.internalUmlService.fetchInstanceByIds(appliedStereotypes, projectId);
    }

    @NotNull
    public List<SlotVo> queryPropertySlots(@NotNull final String projectId,
                                           @NotNull final MetaClassInstance instance,
                                           @NotNull final MetaClassInstance stereotype) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instance: {}, stereotype: {}", projectId, instance, stereotype);
        final String stereotypeId = stereotype.getId();
        final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(projectId,
                this.internalUmlService.getQueryPropertyForm(stereotype,
                        Stream.of(UMLDefinitionConstants.Classifier_feature, UMLDefinitionConstants.Class_extension,
                                UMLDefinitionConstants.Class_ownedAttribute).collect(Collectors.toList()))
        );
        final List<MetaClassInstance> ownedAttributes = mofResultContainer
                .queryListInstanceProperty(stereotypeId, UMLDefinitionConstants.Classifier_feature);

        // 获取stereotype的扩展关系
        final List<MetaClassInstance> extensions = mofResultContainer
                .queryListInstanceProperty(stereotypeId, UMLDefinitionConstants.Class_extension);
        // 通过扩展关系找到baseProperty
        if (CollectionUtils.isNotEmpty(extensions)) {
            mofResultContainer.addMofPropertyResult(this.internalUmlService.queryProperty(
                    projectId,
                    this.internalUmlService.getQueryPropertyForm(extensions, UMLDefinitionConstants.Association_memberEnd)
            ));
            List<MetaClassInstance> baseProperties = extensions.stream()
                    .map(extension -> {
                        final List<MetaClassInstance> memberEnds = mofResultContainer.queryListInstanceProperty(
                                extension.getId(), UMLDefinitionConstants.Association_memberEnd);
                        return memberEnds.stream().findFirst().orElse(null);
                    }).filter(Objects::nonNull)
                    .collect(Collectors.toList());
            // 排除baseProperty
            ownedAttributes.removeAll(baseProperties);
        }
        // 排除ProxyPort的direction
        if (Objects.equals(UMLDefinitionConstants.SysML_ProxyPort, stereotypeId)) {
            List<MetaClassInstance> directions = internalUmlService.queryListInstanceProperty(projectId, stereotype,
                    UMLDefinitionConstants.Class_ownedAttribute).stream().filter(attribute ->
                    Objects.equals(DIRECTION, internalUmlService.queryStringProperty(projectId, attribute,
                            UMLDefinitionConstants.NamedElement_name))).collect(Collectors.toList());
            ownedAttributes.removeAll(directions);
        }
        // 由于Diagram构造型的关系为泛化，则通过stereotype直接得到baseProperty
        final List<MetaClassInstance> attributes = internalUmlService.queryListInstanceProperty(projectId, stereotype,
                UMLDefinitionConstants.Classifier_attribute);
        if (internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.UMLDiagram) &&
                CollectionUtils.isNotEmpty(attributes)) {
            // 排除baseProperty
            ownedAttributes.remove(attributes.get(0));
        }
        mofResultContainer.addMofPropertyResult(
                this.internalUmlService.queryProperty(
                        projectId, this.internalUmlService.getQueryPropertyForm(
                                ownedAttributes, UMLDefinitionConstants.NamedElement_name
                        )
                ));
        // 存在一些baseProperty并不是由关系得到的，粗暴地判断属性名称是不是以"base_"开头而排除
        List<MetaClassInstance> otherBaseProperty = ownedAttributes.stream()
                .filter(attribute -> {
                    String name = mofResultContainer
                            .queryStringProperty(attribute.getId(), UMLDefinitionConstants.NamedElement_name);
                    return StringUtils.isNotEmpty(name) && name.startsWith("base_");
                }).collect(Collectors.toList());
        ownedAttributes.removeAll(otherBaseProperty);
        MetaClassInstance appliedStereotypeInstances = internalUmlService
                .queryInstanceProperty(projectId, instance, UMLDefinitionConstants.Element_appliedStereotypeInstance);
        MetaClassInstance appliedStereotype = null;
        if (Objects.nonNull(appliedStereotypeInstances)) {
            appliedStereotype = appliedStereotypeInstances;
        }
        return makeSlotVos(projectId, appliedStereotype, ownedAttributes);
    }

    @NotNull
    public List<SlotVo> queryPropertySlots(String projectId, String instanceId, String stereotypeId) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}, stereotypeId: {}", projectId, instanceId, stereotypeId);
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(instance)) {
            return Collections.emptyList();
        }
        MetaClassInstance stereotype = internalUmlService.fetchInstance(stereotypeId, projectId);
        if (Objects.isNull(stereotype)) {
            return Collections.emptyList();
        }
        return queryPropertySlots(projectId, instance, stereotype);
    }

    /**
     * 根据构造型属性创建模型属性值
     *
     * @param projectId
     * @param instanceId 属性id
     * @param parentId   元素id
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author xz
     * @date 2022/11/25 17:24
     */
    @NotNull
    public ModelResultVo createSlotBasedOnProperty(String projectId, String instanceId, String parentId) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}, parentId: {}", projectId, instanceId, parentId);
        final Map<String, MetaClassInstance> metaClassInstanceMap = this.internalUmlService.fetchInstances(
                Stream.of(instanceId, parentId).collect(Collectors.toList()), projectId);
        MetaClassInstance property = metaClassInstanceMap.get(instanceId);
        MetaClassInstance parent = metaClassInstanceMap.get(parentId);
        if (property == null) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }
        MetaClassInstance instanceSpecification = this.internalUmlService
                .queryListInstanceProperty(projectId, parent, UMLDefinitionConstants.Element_appliedStereotypeInstance)
                .stream().findFirst().orElse(null);
        if (Objects.nonNull(instanceSpecification)) {
            parentId = instanceSpecification.getId();
        }

        return getModelResultVo(projectId, parentId, property);
    }

    @NotNull
    private ModelResultVo getModelResultVo(String projectId, String parentId, MetaClassInstance property) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, parentId: {}, property: {}", projectId, parentId, property);
        ModelResultVo modelResultVo = new ModelResultVo();

        List<String> stereotypes = null;
        for (Map.Entry<String, List<String>> entry : UAFModelConstantURI.CLASSIFIER_TO_SLOT_STEREOTYPE_CONSTRAINT.entrySet()) {
            if (internalUmlService.checkInstanceType(projectId, property, entry.getKey())) {
                stereotypes = UAFModelConstantURI.CLASSIFIER_TO_SLOT_STEREOTYPE_CONSTRAINT.get(entry.getKey());
            }
        }

        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {
            AddModelDTO addModelDto = new AddModelDTO();
            addModelDto.setParentId(parentId);
            addModelDto.setProjectId(projectId);
            addModelDto.setType(CommandAddType.MODEL.getCode());
            addModelDto.setMetaclass(UMLDefinitionConstants.Slot);
            if (Objects.nonNull(stereotypes)) {
                addModelDto.setApplyStereotypes(stereotypes);
            }
            MetaClassInstance slot = umlService.addModel(addModelDto);
            umlService.updateModel(projectId, slot.getId(),
                    UMLDefinitionConstants.Slot_definingFeature, property);
            transactionService.commit(projectId);
            modelResultVo.setInstanceId(slot.getId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
            modelResultVo.getModifyModel().add(parentId);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }
        return modelResultVo;
    }

    /**
     * 获取当前属性组可展示的属性的列表
     *
     * @param projectId
     * @param propertyGroupId
     * @return java.util.List<com.huawang.mdesign.model.service.vo.PropertyInfoVo>
     * @author xz
     * @date 2022/06/09 11:07
     */
    @NotNull
    public List<PropertyInfoVo> queryPropertyGroupSelectedProperties(String projectId, String propertyGroupId) {
        LogUtil.printOnlineLogs("queryPropertyGroupSelectedProperties -> projectId: {}, propertyGroupId: {}", projectId,
                propertyGroupId);
        MetaClassInstance propertyGroup = internalUmlService.fetchInstance(propertyGroupId, projectId);
        if (propertyGroup == null) {
            return Collections.emptyList();
        }
        MetaClassInstance cus = internalUmlService.queryInstanceProperty(projectId, propertyGroup,
                UMLDefinitionConstants.Element_owner);
        if (!internalUmlService.checkInstanceType(projectId, cus, UMLDefinitionConstants.Customization_Customization)) {
            return Collections.emptyList();
        }

        List<MetaClassInstance> targets = internalUmlService.queryListInstanceProperty(projectId, cus,
                UMLDefinitionConstants.Customization_Customization_customizationTarget);
        if (CollectionUtils.isEmpty(targets)) {
            return Collections.emptyList();
        }

        //查询元类属性、构造型属性、派生属性、自定义属性
        QueryOwnedPropertyForm queryOwnedPropertyForm=QueryOwnedPropertyForm.builder().metaInstances(targets).
                findGeneralCascade(true).findSpecificCascade(false).needOppositeProperty(false).
                excludeRedefinedProperty(true).excludeReadOnlyProperty(false).excludeComputedProperty(false).
                isFindStereotypeProperties(true).isFindCustomizeProperties(true).isFindDerivedProperties(true).build();
        List<String> properties = internalUmlService.getOwnedPropertiesByInstanceId(projectId, queryOwnedPropertyForm);

        // 部分元素的部分属性并不需要要展示
        Set<String> needFilterPropertyIds = Stream.of(
                UMLDefinitionConstants.TableAndMatrix_DiagramTable_rowElements,
                UMLDefinitionConstants.TableAndMatrix_DiagramTable_columnIds,
                UMLDefinitionConstants.TableAndMatrix_DiagramTable_rowsOrder,
                UMLDefinitionConstants.Abstraction_mapping,
                UMLDefinitionConstants.SysML_ItemFlow_activities,
                UMLDefinitionConstants.Customization_DataMapping_mappingConfiguration,
                UMLDefinitionConstants.Namespace_ownedDiagram,
                UMLDefinitionConstants.NumberOwner_customNumberingData).collect(Collectors.toSet());

        List<String> allPropertyIds =  properties.stream().filter(e -> !needFilterPropertyIds.contains(e)).collect(Collectors.toList());

        List<MetaClassInstance> allProperties = internalUmlService.fetchInstanceByIds(allPropertyIds, projectId);

        final List<ModelPropertyInfo> propertyModels = modelPropertyInfoService.createModelPropertyInfoList(projectId
                , allProperties, Stream.of(
                        UMLDefinitionConstants.NamedElement_name,
                        UMLDefinitionConstants.TypedElement_type).collect(Collectors.toList()));
        return propertyModels.stream().map(this::createPropertyInfoVo).collect(Collectors.toList());
    }

    /**
     * 获取当前属性组展示模型的属性
     *
     * @param projectId
     * @param propertyGroupId
     * @return java.util.List<com.huawang.mdesign.model.service.vo.PropertyInfoVo>
     * @author xz
     * @date 2022/06/09 11:10
     */
    @NotNull
    public List<PropertyInfoVo> queryPropertyGroupSelectedColumns(String projectId, String propertyGroupId) {
        LogUtil.printOnlineLogs("queryPropertyGroupSelectedColumns -> projectId: {}, propertyGroupId: {}", projectId,
                propertyGroupId);
        MetaClassInstance propertyGroup = internalUmlService.fetchInstance(propertyGroupId, projectId);
        if (propertyGroup == null) {
            return Collections.emptyList();
        }

        List<String> properties = internalUmlService.queryListStringProperty(projectId, propertyGroup,
                UMLDefinitionConstants.Customization_PropertyGroup_properties);
        if (CollectionUtils.isEmpty(properties)) {
            return Collections.emptyList();
        }

        List<MetaClassInstance> propertyInstances = this.internalUmlService.fetchInstanceByIds(properties, projectId)
                .stream()
                .map(it -> internalUmlService.queryPropertyType(projectId, it.getId()))
                .filter(it -> it != null && !internalUmlService.checkInstanceType(projectId, it,
                        UMLDefinitionConstants.PrimitiveType))
                .collect(Collectors.toList());
        final List<MetaClassInstance> result =
                internalUmlService.queryMetaClassMetaPropertyListWithAllGeneral(propertyInstances,
                        projectId, false, true, true);
        final Map<String, PropertyInfoVo> propertyInfoVos = this.createPropertyInfoVos(
                projectId, result.stream().map(BasicRElement::getId).collect(Collectors.toList()));
        return new ArrayList<>(propertyInfoVos.values());
    }

    @NotNull
    public ModelResultVo createInstanceSpecificationWithSlot(CreateInstanceSpecificationDTO dto) {
        LogUtil.printSerializeOnlineLogs("createInstanceSpecificationWithSlot -> dto: ", dto);
        ValidateDataUtil.isNotEmpty(dto.getInstanceSpecifications());
        final String projectId = dto.getProjectId();
        final String parentId = dto.getOwnerId();
        final List<InstacneSpecificationInfo> instanceSpecificationList = dto.getInstanceSpecifications();
        final List<CommandParameter> parameterList = new ArrayList<>(instanceSpecificationList.size());
        final List<UpdateModelDTO> updateModelDtoList = new ArrayList<>(instanceSpecificationList.size());
        final Map<String, String> instanceSpecificationMap = new HashMap<>(instanceSpecificationList.size());
        ModelResultVo modelResultVo = new ModelResultVo();

        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {

            instanceSpecificationList.forEach(instanceSpecificationInfo -> {
                final CommandParameter commandParameter = CommandParameter.builder()
                        .parentId(parentId)
                        .typeId(UMLDefinitionConstants.InstanceSpecification)
                        .defaultName(instanceSpecificationInfo.getName())
                        .projectId(projectId)
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                parameterList.add(commandParameter);

                final List<MetaClassInstance> classifiers =
                        internalUmlService.fetchInstanceByIds(instanceSpecificationInfo.getClassifierIds(), projectId);
                final UpdateModelDTO updateModelDto = UpdateModelFactory.newInstance(projectId,
                        commandParameter.getInstanceId(), UMLDefinitionConstants.InstanceSpecification_classifier,
                        classifiers);
                updateModelDtoList.add(updateModelDto);

                instanceSpecificationMap.put(instanceSpecificationInfo.getId(), commandParameter.getInstanceId());
            });

            //批量创建实例
            umlService.addModelByBatch(parameterList);
            //批量更新实例的分类器
            umlService.updateModelByBatch(updateModelDtoList);
            int initSize = instanceSpecificationList.stream().mapToInt(it -> it.getSlots().size()).sum();
            final List<CommandParameter> slotParameterList = new ArrayList<>(initSize);
            final List<UpdateModelDTO> updateSlotDtos = new ArrayList<>(initSize);
            final Map<String, SlotInfo> slotToInfo = new HashMap<>(initSize);
            instanceSpecificationList.forEach(instanceSpecificationInfo -> {
                final String instanceId = instanceSpecificationMap.get(instanceSpecificationInfo.getId());
                final List<SlotInfo> slotInfoList = instanceSpecificationInfo.getSlots();
                slotInfoList.forEach(slotInfo -> {
                    CommandParameter slotParameter = CommandParameter.builder()
                            .projectId(projectId)
                            .typeId(UMLDefinitionConstants.Slot)
                            .type(CommandAddType.MODEL)
                            .parentId(instanceId)
                            .instanceId(ModelConstantURI.initInstanceId())
                            .build();
                    slotParameterList.add(slotParameter);

                    final MetaClassInstance property = internalUmlService.fetchInstance(slotInfo.getFeatureId(), projectId);
                    if (property == null) {
                        throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
                    }
                    UpdateModelDTO updateSlotDto = UpdateModelFactory.newInstance(projectId, slotParameter.getInstanceId(),
                            UMLDefinitionConstants.Slot_definingFeature, property);
                    updateSlotDtos.add(updateSlotDto);
                    slotToInfo.put(slotParameter.getInstanceId(), slotInfo);
                });

            });

            if (CollectionUtils.isNotEmpty(slotParameterList)) {
                //批量新增slot
                umlService.addModelByBatch(slotParameterList);
                //批量更新Slot_definingFeature
                umlService.updateModelByBatch(updateSlotDtos);
                List<UpdateSlotValueDto> createSlots = slotToInfo.entrySet().stream().map(entry -> {
                    UpdateSlotValueDto updateSlotValueDto = new UpdateSlotValueDto();
                    updateSlotValueDto.setSlotId(entry.getKey());
                    updateSlotValueDto.setValues(entry.getValue().getValues().stream().map(slotValueInfo -> {
                        SlotValueInfo newSlotValue = new SlotValueInfo();
                        newSlotValue.setValue(getSlotValue(instanceSpecificationMap, slotValueInfo.getType(),
                                slotValueInfo.getValue()));
                        newSlotValue.setType(slotValueInfo.getType());
                        return newSlotValue;
                    }).collect(Collectors.toList()));
                    return updateSlotValueDto;
                }).collect(Collectors.toList());
                internalSpecificationService.createValueSpecificationToSlotByBatch(projectId, createSlots);
            }
            transactionService.commit(projectId);
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
            modelResultVo.setModifyModel(new HashSet<>());
            modelResultVo.setModifyModelAndProperties(new ArrayList<>());
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

    @Nullable
    private static Object getSlotValue(Map<String, String> instanceSpecificationMap, String typeId, Object value) {
        LogUtil.printOnlineLogs("typeId: {}, value: {}", typeId, value);
        if (Objects.isNull(value)) {
            return null;
        }

        if (!UMLDefinitionConstants.InstanceValue.equals(typeId)) {
            return value;
        }

        String realValue = (String) value;
        if (instanceSpecificationMap.containsKey(realValue)) {
            return instanceSpecificationMap.get(realValue);
        } else {
            return value;
        }
    }

    @NotNull
    public ModelResultVo deleteInstanceSpecificationsUnderOwner(String projectId, String ownerId) {
        LogUtil.printOnlineLogs("projectId: {}, ownerId: {}", projectId, ownerId);
        ModelResultVo modelResultVo = new ModelResultVo();

        LocalTransaction transaction = transactionService.createTransaction(projectId, DELETE_MODEL);

        MetaClassInstance owner = internalUmlService.fetchInstance(ownerId, projectId);
        if (Objects.isNull(owner)) {
            return modelResultVo;
        }


        List<MetaClassInstance> childrenList = internalUmlService.getChildrenCascade(projectId, owner, false);
        if (CollectionUtils.isEmpty(childrenList)) {
            return modelResultVo;
        }

        Map<String, Set<String>> givenTypes = internalUmlService.getGivenTypes(projectId, childrenList);
        List<MetaClassInstance> instanceSpecifications = childrenList.stream().filter(child ->
                givenTypes.get(child.getId()).contains(UMLDefinitionConstants.InstanceSpecification)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(instanceSpecifications)) {
            return modelResultVo;
        }

        try {
            List<String> instanceSpecificationIds = instanceSpecifications.stream().map(BasicRElement::getId).collect(Collectors.toList());
            DeleteModelDTO deleteModelDto = new DeleteModelDTO();
            deleteModelDto.setProjectId(projectId);
            deleteModelDto.setIds(instanceSpecificationIds);
            deleteService.deleteModels(projectId, instanceSpecificationIds);
            transactionService.commit(projectId);
            InstanceVoUtils.fillDeleteResultVo(deleteModelDto, modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }

        return modelResultVo;
    }


    /**
     * 分类器的包含的slot
     *
     * @param projectId
     * @param classifierId
     * @return java.util.List<com.huawang.mdesign.model.service.vo.PreviewSlotVo>
     */
    @NotNull
    public List<PreviewSlotVo> queryTypeSlots(String projectId, String classifierId) {
        LogUtil.printOnlineLogs("projectId: {}, classifierId: {}", projectId, classifierId);
        MetaClassInstance classifier = internalUmlService.fetchInstance(classifierId, projectId);
        if (classifier == null) {
            return Collections.emptyList();
        }
        List<MetaClassInstance> allClassifiers = internalUmlService.findGeneralsCascade(projectId, classifier.getId(), true);
        List<MetaClassInstance> classOwnedAttributes = internalUmlService.queryProperty(projectId, allClassifiers, UMLDefinitionConstants.Class_ownedAttribute);

        MofResultContainer attributeContainer = internalUmlService.getMofResultContainer(
                projectId, classOwnedAttributes, UMLDefinitionConstants.A_redefinedProperty_property_property);

        // 如果重定义属性存在于继承来的属性中，则过滤被重定义属性
        List<MetaClassInstance> allAttributes = classOwnedAttributes.stream()
                .filter(it -> {
                    List<MetaClassInstance> redefinedProperties = attributeContainer.queryListInstanceProperty(
                            it.getId(), UMLDefinitionConstants.A_redefinedProperty_property_property);
                    return redefinedProperties.stream().noneMatch(classOwnedAttributes::contains);
                })
                .collect(Collectors.toList());
        final List<ModelPropertyInfo> attributeModels = modelPropertyInfoService.createModelPropertyInfoList(
                projectId,
                allAttributes,
                Stream.of(UMLDefinitionConstants.Property_defaultValue,
                                UMLDefinitionConstants.NamedElement_name,
                                UMLDefinitionConstants.TypedElement_type,
                                UMLDefinitionConstants.MultiplicityElement_multiplicity)
                        .collect(Collectors.toList()));
        return makePreviewSlotVos(projectId, attributeModels);
    }

    @NotNull
    private List<PreviewSlotVo> makePreviewSlotVos(String projectId, List<ModelPropertyInfo> attributeModels) {
        LogUtil.printOnlineLogs("projectId: {}", projectId);
        List<MetaClassInstance> attributeInstances = attributeModels.stream().map(ModelPropertyInfo::getInstance).collect(Collectors.toList());
        List<MetaClassInstance> typeInstances = attributeModels.stream().map(modelPropertyInfo -> modelPropertyInfo.queryInstanceValue(UMLDefinitionConstants.TypedElement_type)).filter(Objects::nonNull).collect(Collectors.toList());
        List<MetaClassInstance> allInstance = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(attributeInstances)) {
            allInstance.addAll(attributeInstances);
        }
        if (CollectionUtils.isNotEmpty(typeInstances)) {
            allInstance.addAll(typeInstances);
        }
        Map<String, String> iconMap = modelPropertyInfoService.queryIconBatch(projectId, allInstance);
        MofResultContainer nameContainer = internalUmlService.queryProperty(projectId, internalUmlService.getQueryPropertyForm(typeInstances, UMLDefinitionConstants.NamedElement_name));
        List<MetaClassInstance> typeOwnedAttributes = typeInstances.stream().filter(type -> internalUmlService.canAutoInstantiate(projectId, type.getId()) && InstanceUtils.isInstanceInteractivelyCreated(type)).collect(Collectors.toList());
        MofResultContainer ownedAttributeContainer = internalUmlService.queryProperty(projectId, internalUmlService.getQueryPropertyForm(typeOwnedAttributes, UMLDefinitionConstants.Class_ownedAttribute));
        List<MetaClassInstance> defaultValueInstances = attributeModels.stream().map(modelPropertyInfo -> modelPropertyInfo.queryInstanceValue(UMLDefinitionConstants.Property_defaultValue)).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, ValueSpecificationInfo> defaultValueMap = internalSpecificationService.queryValueFromValueSpecification(projectId, defaultValueInstances);
        return attributeModels.stream().map(model -> {
            PreviewSlotVo vo = new PreviewSlotVo();
            vo.setPropertyId(model.getInstanceId());
            vo.setPropertyIcon(iconMap.get(model.getInstanceId()));
            vo.setPropertyName(model.queryStringValue(UMLDefinitionConstants.NamedElement_name));
            MetaClassInstance type = model.queryInstanceValue(UMLDefinitionConstants.TypedElement_type);
            if (Objects.nonNull(type)) {
                vo.setTypeName(nameContainer.queryStringProperty(type.getId(), UMLDefinitionConstants.NamedElement_name));
                vo.setTypeId(type.getId());
                vo.setTypeIcon(iconMap.get(type.getId()));
                if (CollectionUtils.isNotEmpty(ownedAttributeContainer.queryListInstanceProperty(type.getId(), UMLDefinitionConstants.Class_ownedAttribute))) {
                    vo.setHasChild(true);
                }
            }
            String multiplicity = model.queryStringValue(UMLDefinitionConstants.MultiplicityElement_multiplicity);
            if (Objects.nonNull(multiplicity)) {
                vo.setMultiplicity(multiplicity);
                vo.setLowerValue(getMultiplicityLowerValue(multiplicity));
            }

            MetaClassInstance defaultValue = model.queryInstanceValue(UMLDefinitionConstants.Property_defaultValue);
            if (Objects.nonNull(defaultValue)) {
                ValueSpecificationInfo valueSpecificationInfo = defaultValueMap.get(defaultValue.getId());
                if (Objects.equals(valueSpecificationInfo.getMetaclass(), UMLDefinitionConstants.ElementValue)
                        || Objects.equals(valueSpecificationInfo.getMetaclass(), UMLDefinitionConstants.InstanceValue)) {
                    vo.setDefaultValue(valueSpecificationInfo.getElementId());
                } else {
                    vo.setDefaultValue(valueSpecificationInfo.getValue());
                }
                String defaultValueType = defaultValue.getMetaClass().getId();
                vo.setDefaultValueType(convertToSlotType(projectId, defaultValueType, type));
            }

            String typeName = internalSpecificationService.getPropertyTypeName(projectId, model.getInstance());
            vo.setDataType(convertToSlotType(projectId, typeName, type));
            return vo;
        }).collect(Collectors.toList());
    }

    @NotNull
    private String convertToSlotType(String projectId, String typeName, MetaClassInstance type) {
        LogUtil.printOnlineLogs("projectId: {}, typeName: {}", projectId, typeName);
        switch (typeName) {
            case UMLDefinitionConstants.LiteralBoolean:
                return SlotDataType.BOOLEAN.value();
            case UMLDefinitionConstants.LiteralReal:
                return SlotDataType.REAL.value();
            case UMLDefinitionConstants.LiteralInteger:
                return SlotDataType.INTEGER.value();
            case UMLDefinitionConstants.InstanceValue: {
                if (type != null && internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Enumeration)) {
                    return SlotDataType.ENUM.value();
                } else {
                    return SlotDataType.INSTANCE.value();
                }
            }
            case UMLDefinitionConstants.ElementValue: {
                return SlotDataType.INSTANCE.value();
            }
            default:
                return SlotDataType.STRING.value();
        }
    }

    @NotNull
    private static String getMultiplicityLowerValue(String multiplicity) {
        LogUtil.printOnlineLogs("getMultiplicityLowerValue -> multiplicity: ", multiplicity);
        if (multiplicity.contains("..")) {
            String[] multiplicityArr = multiplicity.split("\\.\\.");
            return multiplicityArr[0];
        }
        return multiplicity;
    }

    @NotNull
    @Transactional
    public ModelResultVo batchCreateInstances(BatchCreateInstanceDTO dto) {
        LogUtil.printSerializeOnlineLogs("batchCreateInstances -> dto: ", dto);
        ModelResultVo modelResultVo = new ModelResultVo();
        String projectId = dto.getProjectId();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        try {
            List<String> slotIds = new ArrayList<>();
            createInstantiate(projectId, dto.getInstanceInfoDTO(), dto.getPackageId(), slotIds);
            createDiagram(dto);
            transactionService.commit(projectId);
            Set<String> addIds = new LinkedHashSet<>(slotIds);
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction, addIds);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

    @Nullable
    private MetaClassInstance createSlot(String projectId, String parentId, MetaClassInstance property, MetaClassInstance type, String multiplicity) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, parentId: {}, property: {}, type: {}, multiplicity: {}",
                projectId, parentId, property, type, multiplicity);
        // 1.如果枚举类型，没有有枚举值，不设置槽
        // 2.多重性为0 ，不设置槽
        if (Objects.nonNull(type) && internalUmlService.getGivenTypes(projectId, type).contains(UMLDefinitionConstants.Enumeration)) {
            List<MetaClassInstance> metaClassInstances = internalUmlService.queryListInstanceProperty(projectId, type, UMLDefinitionConstants.Enumeration_ownedLiteral);
            if (CollectionUtils.isEmpty(metaClassInstances)) {
                return null;
            }
        }
        if (!canSetSlotValue(multiplicity)) {
            return null;
        }

        AddModelDTO addModelDto = new AddModelDTO();
        addModelDto.setParentId(parentId);
        addModelDto.setProjectId(projectId);
        addModelDto.setType(CommandAddType.MODEL.getCode());
        addModelDto.setMetaclass(UMLDefinitionConstants.Slot);
        MetaClassInstance slot = umlService.addModel(addModelDto);
        umlService.updateModel(projectId, slot.getId(), UMLDefinitionConstants.Slot_definingFeature, property);
        return slot;
    }

    private void updateClassifier(String projectId, InstanceInfoDTO instanceInfoDTO, MetaClassInstance instantiate) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceInfoDTO: {}, instantiate: {}", projectId, instanceInfoDTO,
                instantiate);
        if (Objects.isNull(instanceInfoDTO.getTypeId())) {
            return;
        }
        MetaClassInstance classifier = this.internalUmlService.fetchInstance(instanceInfoDTO.getTypeId(), projectId);
        this.umlService.updateModel(projectId, instantiate.getId(), UMLDefinitionConstants.InstanceSpecification_classifier, Collections.singletonList(classifier));
    }

    /**
     * 根据instanceInfoDTO树，创建实例
     *
     * @param projectId
     * @param instanceInfoDTO
     * @param parentId
     * @return
     */
    @NotNull
    private MetaClassInstance createInstantiate(String projectId, InstanceInfoDTO instanceInfoDTO, String parentId,
                                                List<String> slotIds) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceInfoDTO: {}, parentId: {}, slotIds: {}",
                projectId, instanceInfoDTO, parentId, slotIds);
        // 1. 创建实例规格
        MetaClassInstance instantiate = createInstanceSpecification(projectId, instanceInfoDTO, parentId);
        // 2. 修改实例规格 InstanceSpecification-classifier 为当前classifier
        updateClassifier(projectId, instanceInfoDTO, instantiate);
        List<InstanceInfoDTO> children = instanceInfoDTO.getChildren();
        if (CollectionUtils.isEmpty(children)) {
            return instantiate;
        }
        List<String> propertyIds = children.stream().map(InstanceInfoDTO::getPropertyId).collect(Collectors.toList());
        Map<String, MetaClassInstance> propertyInstanceMap = internalUmlService.fetchInstances(propertyIds, projectId);
        MofResultContainer propertyContainer = internalUmlService.queryProperty(projectId,
                internalUmlService.getQueryPropertyForm(new ArrayList<>(propertyInstanceMap.values()),
                        Arrays.asList(UMLDefinitionConstants.MultiplicityElement_multiplicity, UMLDefinitionConstants.TypedElement_type)));

        children.forEach(child -> {
            // 3. 根据propertyId创建对应插槽
            checkLevel(child, instanceInfoDTO);
            MetaClassInstance property = propertyInstanceMap.get(child.getPropertyId());
            if(Objects.isNull(property)){
                return;
            }
            MetaClassInstance type = propertyContainer.queryInstanceProperty(property.getId(), UMLDefinitionConstants.TypedElement_type);
            String multiplicity = propertyContainer.queryStringProperty(property.getId(), UMLDefinitionConstants.MultiplicityElement_multiplicity);
            MetaClassInstance slot = createSlot(projectId, instantiate.getId(), property, type, multiplicity);
            if (Objects.nonNull(slot)) {
                slotIds.add(slot.getId());
            }

            int valueSpecificationNum = getSpecificationValueNum(multiplicity);
            for (int i = 1; i <= valueSpecificationNum; i++) {
                Object value = child.getValues();
                if (valueSpecificationNum > DEFAULT_SPECIFICATION_VALUE_NUM) {
                    child.setOrder(i);
                }
                child.getInstanceNameGenerator().init(instanceInfoDTO);
                String typeId = child.getTypeId();
                if (StringUtils.isNotEmpty(typeId) && internalUmlService.canAutoInstantiate(projectId, typeId)) {
                    MetaClassInstance childInstantiate = createInstantiate(projectId, child, parentId, slotIds);
                    value = childInstantiate.getId();
                }
                if (canSetSlotValue(multiplicity) && Objects.nonNull(slot)) {
                    if(value instanceof List){
                        List<Object> list = ((List<Object>)value);
                        //setup 多值的情况
                        list.forEach(v -> setValueSpecification(projectId, slot, v, type));
                    }else {
                        setValueSpecification(projectId, slot, value, type);
                    }
                }
            }
        });
        return instantiate;
    }

    @NotNull
    private Object getValueOrDefault(String projectId, String value, MetaClassInstance type) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, value: {}, type: {}", projectId, value, type);
        String typeId = type.getId();
        String metaClass = type.getMetaClass().getId();
        switch (metaClass) {
            case "PrimitiveType": {
                Object value1 = getObject(value, typeId);
                if (value1 != null) {
                    return value1;
                }
                break;
            }
            case "DataType": {
                try {
                    return Double.valueOf(value);
                } catch (NumberFormatException e) {
                    log.warn("", e);
                    return "0.0";
                }
            }
            case "Enumeration": {
                List<MetaClassInstance> metaClassInstances = internalUmlService.queryListInstanceProperty(projectId, type, UMLDefinitionConstants.Enumeration_ownedLiteral);
                if (CollectionUtils.isNotEmpty(metaClassInstances)) {
                    Optional<MetaClassInstance> optional = metaClassInstances.stream().filter(metaClassInstance -> Objects.equals(metaClassInstance.getId(), value)).findAny();
                    if (optional.isPresent()) {
                        return optional.get();
                    } else {
                        return metaClassInstances.get(0).getId();
                    }
                }
                break;
            }
            default:
                break;
        }
        return value;
    }

    @Nullable
    private static Object getObject(String value, String typeId) {
        LogUtil.printOnlineLogs("value: {}, typeId: {}", value, typeId);
        switch (typeId) {
            case "Boolean":
                return "true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value);
            case "Integer":
                try {
                    return Integer.valueOf(value);
                } catch (NumberFormatException e) {
                    log.warn("", e);
                    return 0;
                }
            case "Real":
                try {
                    return Double.valueOf(value);
                } catch (NumberFormatException e) {
                    log.warn("", e);
                    return "0.0";
                }
            case "String":
            case "UnlimitedNatural":
            default:
                break;
        }
        return null;
    }

    private void setValueSpecification(String projectId, MetaClassInstance slot, Object value, MetaClassInstance type) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, slot: {}, value: {}, type: {}", projectId, slot, value, type);
        if (!(value instanceof MetaClassInstance)  && Objects.nonNull(type)) {
            String valueStr = String.valueOf(value);
            value = getValueOrDefault(projectId, valueStr, type);
        }
        internalSpecificationService.createValueSpecificationBySlot(projectId, slot, value, null, null);
    }

    /**
     * 是否能为槽设置值 ，只有多重性为0，不能设置值
     *
     * @param multiplicity
     * @return
     */
    private static boolean canSetSlotValue(String multiplicity) {
        LogUtil.printOnlineLogs("canSetSlotValue -> multiplicity: ", multiplicity);
        if (Objects.isNull(multiplicity)) {
            return true;
        }
        String multiplicityLowerValue = getMultiplicityLowerValue(multiplicity);
        return !Objects.equals("0", multiplicityLowerValue) || multiplicity.contains("..");
    }

    private static int getSpecificationValueNum(String multiplicity) {
        LogUtil.printOnlineLogs("getSpecificationValueNum -> multiplicity: ", multiplicity);
        if (StringUtils.isEmpty(multiplicity)) {
            return DEFAULT_SPECIFICATION_VALUE_NUM;
        }
        String lowerValue = getMultiplicityLowerValue(multiplicity);
        if (Objects.equals(lowerValue, "0")) {
            return DEFAULT_SPECIFICATION_VALUE_NUM;
        }

        try {
            return Integer.parseInt(lowerValue);
        } catch (NumberFormatException var3) {
            log.warn("转换失败", var3);
            return DEFAULT_SPECIFICATION_VALUE_NUM;
        }
    }

    /**
     * 给child设置一些属性字段
     *
     * @param child
     * @param parent
     */
    private static void checkLevel(InstanceInfoDTO child, InstanceInfoDTO parent) {
        LogUtil.printSerializeOnlineLogs("child: {}, parent: {}", child, parent);
        int nextLevel = parent.getLevel() + 1;
        if (nextLevel >= MAX_LEVEL_LIMIT) {
            throw AbortExecutionException.build(BATCH_CREATE_INSTANCE_EXCEED_MAX_LEVEL);
        }
        // 设置层级
        child.setLevel(nextLevel);
    }

    @NotNull
    private MetaClassInstance createInstanceSpecification(String projectId, InstanceInfoDTO instanceInfoDTO, String parentId) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instanceInfoDTO: {}, parentId: {}", projectId, instanceInfoDTO,
                parentId);
        AddModelDTO addModelDto = new AddModelDTO();
        addModelDto.setParentId(parentId);
        addModelDto.setProjectId(projectId);
        addModelDto.setType(CommandAddType.MODEL.getCode());
        addModelDto.setMetaclass(UMLDefinitionConstants.InstanceSpecification);
        String defaultName = elementNameService.fetchDefaultName(projectId, UMLDefinitionConstants.InstanceSpecification,
                parentId, instanceInfoDTO.getInstanceNameGenerator().generateInstanceName(), "");
        addModelDto.setDefaultName(defaultName);
        return umlService.addModel(addModelDto);
    }

    private void createDiagram(BatchCreateInstanceDTO dto) {
        LogUtil.printSerializeOnlineLogs("createDiagram -> dto: ", dto);
        BatchCreateInstanceDTO.DiagramInfo diagram = dto.getDiagram();
        if (diagram == null) {
            return;
        }
        if (CollectionUtils.isEmpty(diagram.getApplyStereotypes())) {
            return;
        }
        AddModelDTO addModelDto = new AddModelDTO();
        addModelDto.setParentId(diagram.getParentId());
        addModelDto.setProjectId(diagram.getProjectId());
        addModelDto.setType(CommandAddType.MODEL.getCode());
        addModelDto.setMetaclass(diagram.getMetaclass());
        addModelDto.setApplyStereotypes(dto.getDiagram().getApplyStereotypes());
        String name = elementNameService.fetchDefaultName(diagram.getProjectId(), diagram.getApplyStereotypes().get(0),
                diagram.getParentId(), diagram.getDefaultName(), "");
        addModelDto.setDefaultName(name);
        umlService.addModel(addModelDto);
    }

    @NotNull
    public List<String> queryAllApplyConstraints(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("queryApplyConstraints -> projectId: {}, instanceId: {}", projectId, instanceId);
        MetaClassInstance instance = internalUmlService.fetchInstance(instanceId, projectId);
        if (instance == null) {
            return Collections.emptyList();
        }

        List<MetaClassInstance> constraints = new ArrayList<>();
        constraints.addAll(internalUmlService.queryListInstanceProperty(projectId, instance, UMLDefinitionConstants.Element_constraints));
        if (internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.SysML_Block)) {
            List<MetaClassInstance> ownedAttributeList = internalUmlService.queryListInstanceProperty(projectId, instance,
                    UMLDefinitionConstants.Class_ownedAttribute);
            if (CollectionUtils.isNotEmpty(ownedAttributeList)) {
                QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(ownedAttributeList, UMLDefinitionConstants.Element_constraints);
                MofResultContainer mofResultContainer = internalUmlService.queryProperty(projectId, queryPropertyForm);
                constraints.addAll(ownedAttributeList.stream().flatMap(ownedAttribute ->
                        mofResultContainer.queryListInstanceProperty(ownedAttribute.getId(), UMLDefinitionConstants.Element_constraints).stream()).collect(Collectors.toList()));
            }
        }

        return constraints.stream().filter(Objects::nonNull).map(BasicRElement::getId).distinct().collect(Collectors.toList());
    }


}
